<?php

namespace app\common\library;

use TencentCloud\Common\Credential;
use TencentCloud\Common\Exception\TencentCloudSDKException;
use TencentCloud\Common\Profile\ClientProfile;
use TencentCloud\Common\Profile\HttpProfile;

use TencentCloud\Sms\V20210111\Models\SendSmsRequest;
use TencentCloud\Sms\V20210111\SmsClient;
use TencentCloud\Vms\V20200902\Models\SendCodeVoiceRequest;
use TencentCloud\Vms\V20200902\Models\SendTtsVoiceRequest;
use TencentCloud\Vms\V20200902\VmsClient;
use think\Hook;

/**
 * 短信验证码类
 */
class Sms
{

    /**
     * 验证码有效时长
     * @var int
     */
    protected static $expire = 120;

    /**
     * 最大允许检测的次数
     * @var int
     */
    protected static $maxCheckNums = 10;

    /**
     * 获取最后一次手机发送的数据
     *
     * @param int $mobile 手机号
     * @param string $event 事件
     * @return  Sms
     */
    public static function get($mobile, $event = 'default')
    {
        $sms = \app\common\model\Sms::
        where(['mobile' => $mobile, 'event' => $event])
            ->order('id', 'DESC')
            ->find();
        Hook::listen('sms_get', $sms, null, true);
        return $sms ? $sms : null;
    }

    /**
     * 发送验证码
     *
     * @param int $mobile 手机号
     * @param int $code 验证码,为空时将自动生成4位数字
     * @param string $event 事件
     * @return  boolean
     */
    public static function send($mobile, $code = null, $event = 'default')
    {
        $code = is_null($code) ? mt_rand(1000, 9999) : $code;
        $time = time();
        $ip = request()->ip();
        $sms = \app\common\model\Sms::create(['event' => $event, 'mobile' => $mobile, 'code' => $code, 'ip' => $ip, 'createtime' => $time]);
        $result = Hook::listen('sms_send', $sms, null, true);
        if (!$result) {
            $sms->delete();
            return false;
        }
        return true;
    }

    /**
     * 发送通知
     *
     * @param mixed $mobile 手机号,多个以,分隔
     * @param string $msg 消息内容
     * @param string $template 消息模板
     * @return  boolean
     */
    public static function notice($mobile, $msg = '', $template = null)
    {
        $params = [
            'mobile' => $mobile,
            'msg' => $msg,
            'template' => $template
        ];
        $result = Hook::listen('sms_notice', $params, null, true);
        return $result ? true : false;
    }

    /**
     * 校验验证码
     *
     * @param int $mobile 手机号
     * @param int $code 验证码
     * @param string $event 事件
     * @return  boolean
     */
    public static function check($mobile, $code, $event = 'default')
    {
        $time = time() - self::$expire;
        $sms = \app\common\model\Sms::where(['mobile' => $mobile, 'event' => $event])
            ->order('id', 'DESC')
            ->find();
        if ($sms) {
            if ($sms['createtime'] > $time && $sms['times'] <= self::$maxCheckNums) {
                $correct = $code == $sms['code'];
                if (!$correct) {
                    $sms->times = $sms->times + 1;
                    $sms->save();
                    return false;
                } else {
                    $result = Hook::listen('sms_check', $sms, null, true);
                    return $result;
                }
            } else {
                // 过期则清空该手机验证码
                self::flush($mobile, $event);
                return false;
            }
        } else {
            return false;
        }
    }

    /**
     * 清空指定手机号验证码
     *
     * @param int $mobile 手机号
     * @param string $event 事件
     * @return  boolean
     */
    public static function flush($mobile, $event = 'default')
    {
        \app\common\model\Sms::
        where(['mobile' => $mobile, 'event' => $event])
            ->delete();
        Hook::listen('sms_flush');
        return true;
    }

    /**
     * 发送验证码
     *
     * @param int|null $code 验证码,为空时将自动生成6位数字
     * @return SendSmsRequest|\TencentCloud\Sms\V20210111\Models\SendSmsResponse
     */
    public static function txSend($phone, int $code = null)
    {
        $code = is_null($code) ? mt_rand(100000, 999999) : $code;

        try {
            /* 必要步骤：
             * 实例化一个认证对象，入参需要传入腾讯云账户密钥对secretId，secretKey。
             * 这里采用的是从环境变量读取的方式，需要在环境变量中先设置这两个值。
             * 你也可以直接在代码中写死密钥对，但是小心不要将代码复制、上传或者分享给他人，
             * 以免泄露密钥对危及你的财产安全。
             * CAM密匙查询: https://console.cloud.tencent.com/cam/capi*/
            $cred = new Credential("AKIDQfeMnwoPikVzC7l8E3aqpYzA4g03pKXT", "g4B0YpoWw5wWord9NKzNTIq64lAI9j11");
            //$cred = new Credential(getenv("TENCENTCLOUD_SECRET_ID"), getenv("TENCENTCLOUD_SECRET_KEY"));
            // 实例化一个http选项，可选的，没有特殊需求可以跳过
            $httpProfile = new HttpProfile();
            $httpProfile->setReqMethod("GET");  // post请求(默认为post请求)
            $httpProfile->setReqTimeout(30);    // 请求超时时间，单位为秒(默认60秒)
            $httpProfile->setEndpoint("sms.tencentcloudapi.com");  // 指定接入地域域名(默认就近接入)
            // 实例化一个client选项，可选的，没有特殊需求可以跳过
            $clientProfile = new ClientProfile();
            $clientProfile->setSignMethod("TC3-HMAC-SHA256");  // 指定签名算法(默认为HmacSHA256)
            $clientProfile->setHttpProfile($httpProfile);
            // 实例化要请求产品(以sms为例)的client对象,clientProfile是可选的
            // 第二个参数是地域信息，可以直接填写字符串 ap-guangzhou，或者引用预设的常量
            $client = new SmsClient($cred, "ap-guangzhou", $clientProfile);
            // 实例化一个 sms 发送短信请求对象,每个接口都会对应一个request对象。
            $req = new SendSmsRequest();
            /* 填充请求参数,这里request对象的成员变量即对应接口的入参
            * 你可以通过官网接口文档或跳转到request对象的定义处查看请求参数的定义
            * 基本类型的设置:
            * 帮助链接：
            * 短信控制台: https://console.cloud.tencent.com/smsv2
            * sms helper: https://cloud.tencent.com/document/product/382/3773 */
            /* 短信应用ID: 短信SdkAppId在 [短信控制台] 添加应用后生成的实际SdkAppId，示例如1400006666 */
            $req->SmsSdkAppId = "1400531493";
            /* 短信签名内容: 使用 UTF-8 编码，必须填写已审核通过的签名，签名信息可登录 [短信控制台] 查看 */
            $req->SignName = "拇指生活";
            /* 短信码号扩展号: 默认未开通，如需开通请联系 [sms helper] */
            $req->ExtendCode = "0";
            /* 下发手机号码，采用 E.164 标准，+[国家或地区码][手机号]
             * 示例如：+8613711112222， 其中前面有一个+号 ，86为国家码，13711112222为手机号，最多不要超过200个手机号*/
            $req->PhoneNumberSet = array("+86" . $phone);

            /* 国际/港澳台短信 SenderId: 国内短信填空，默认未开通，如需开通请联系 [sms helper] */
            //$req->SenderId = "xxx";
            /* 用户的 session 内容: 可以携带用户侧 ID 等上下文信息，server 会原样返回 */
            $req->SessionContext = $code;

            /* 模板 ID: 必须填写已审核通过的模板 ID。模板ID可登录 [短信控制台] 查看 */
            $req->TemplateId = "984457";
            /* 模板参数: 若无模板参数，则设置为空*/
            $req->TemplateParamSet = [$code];
            // 通过client对象调用SendSms方法发起请求。注意请求方法名与请求对象是对应的
            // 返回的resp是一个SendSmsResponse类的实例，与请求对象对应
            // 输出json格式的字符串回包
            // print_r($resp->toJsonString());
            // 也可以取出单个值。
            // 您可以通过官网接口文档或跳转到response对象的定义处查看返回字段的定义
            //print_r($resp->TotalCount);
            return $client->SendSms($req);
        } catch (TencentCloudSDKException $e) {
            echo $e;
        }
        return false;
    }

    /**
     * 发送语音消息
     *
     * @param int|null $code 验证码,为空时将自动生成6位数字
     * @return \TencentCloud\Vms\V20200902\Models\SendTtsVoiceResponse
     */
    public static function txSendMsgVoice($phone)
    {
        try {
            /* 必要步骤：
     * 实例化一个认证对象，入参需要传入腾讯云账户密钥对 secretId 和 secretKey
     * 本示例采用从环境变量读取的方式，需要预先在环境变量中设置这两个值
     * 您也可以直接在代码中写入密钥对，但需谨防泄露，不要将代码复制、上传或者分享给他人
     * CAM 密钥查询：https://console.cloud.tencent.com/cam/capi
     */
            $cred = new Credential("AKIDQfeMnwoPikVzC7l8E3aqpYzA4g03pKXT", "g4B0YpoWw5wWord9NKzNTIq64lAI9j11");
            //$cred = new Credential(getenv("TENCENTCLOUD_SECRET_ID"), getenv("TENCENTCLOUD_SECRET_KEY"));
            // 实例化一个 http 选项，可选，无特殊需求时可以跳过
            $httpProfile = new HttpProfile();
            $httpProfile->setReqMethod("POST");  // POST 请求（默认为 POST 请求）
            $httpProfile->setReqTimeout(30);    // 请求超时时间，单位为秒（默认60秒）
            $httpProfile->setEndpoint("vms.tencentcloudapi.com");  // 指定接入地域域名（默认就近接入）
            // 实例化一个 client 选项，可选，无特殊需求时可以跳过
            $clientProfile = new ClientProfile();
            $clientProfile->setSignMethod("TC3-HMAC-SHA256");  // 指定签名算法（默认为 TC3-HMAC-SHA256）
            $clientProfile->setHttpProfile($httpProfile);
            /* 实例化 VMS 的 client 对象，clientProfile 是可选的
            * 第二个参数是地域信息，可以直接填写字符串ap-guangzhou，或者引用预设的常量
            */
            $client = new VmsClient($cred, "ap-guangzhou", $clientProfile);
            // 实例化一个 VMS 发送短信请求对象，每个接口都会对应一个 request 对象。
            $req = new SendTtsVoiceRequest();
            /* 填充请求参数，这里 request 对象的成员变量即对应接口的入参
            * 您可以通过官网接口文档或跳转到 request 对象的定义处查看请求参数的定义
            * 基本类型的设置:
              * 帮助链接：
              * 语音消息控制台：https://console.cloud.tencent.com/vms
              * vms helper：https://cloud.tencent.com/document/product/1128/37720 */
            // 模板 ID，必须填写在控制台审核通过的模板 ID，可登陆 [语音消息控制台] 查看模板 ID
            $req->TemplateId = "1000125";
            // 模板参数，若模板没有参数，请提供为空数组
            $req->TemplateParamSet = array();
            /* 被叫手机号码，采用 e.164 标准，格式为+[国家或地区码][用户号码]
                * 例如：+8613711112222，其中前面有一个+号，86为国家码，13711112222为手机号 */
            $req->CalledNumber = "+86" . $phone;
            // 在语音控制台添加应用后生成的实际SdkAppid，示例如1400006666
            $req->VoiceSdkAppid = "1400531451";
            // 播放次数，可选，最多3次，默认2次
            $req->PlayTimes = 2;
            // 用户的 session 内容，腾讯 server 回包中会原样返回
            //$req->SessionContext = "xxxx";
            // 通过 client 对象调用 SendTtsVoice 方法发起请求。注意请求方法名与请求对象是对应的
            return $client->SendTtsVoice($req);
            /* // 输出 JSON 格式的字符串回包
             print_r($resp->toJsonString());
             // 可以取出单个值，您可以通过官网接口文档或跳转到 response 对象的定义处查看返回字段的定义
             print_r($resp->RequestId);*/
        } catch (TencentCloudSDKException $e) {
            echo $e;
        }
        return false;
    }
}
